package org.jaaksi.demo.ptr.ui.test.rxjava;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
import java.io.IOException;
import java.util.Collections;
import link.module.AgentInfo;
import link.module.ConfigInfoVo;
import link.module.TokenInfo;
import org.jaaksi.demo.ptr.R;
import org.jaaksi.demo.ptr.api.MockApi;
import org.jaaksi.demo.ptr.bean.Student;
import org.jaaksi.demo.ptr.bean.User;
import org.jaaksi.demo.ptr.bean.response.Result;
import org.jaaksi.demo.ptr.util.DataParseUtil;
import org.jaaksi.demo.ptr.util.LogUtil;
import org.jaaksi.demo.ptr.util.RawUtils;
import retrofit.util.ServiceGenerator;
import retrofit2.Call;
import retrofit2.Response;
import rx.Observable;
import rx.Scheduler;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.schedulers.Schedulers;

public class LoginActivity extends FragmentActivity {
  private Result<AgentInfo> agentInfoResult;
  private Result<ConfigInfoVo> configInfoVoResult;
  private final String TAG = "TestRxJavaActivity";

  private Call<Result<TokenInfo>> loginCall;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  }

  private boolean checkConfig(Result<ConfigInfoVo> result) {
    if (result != null && result.hasData()) {
      if (result.data.tab != null && result.data.tab.size() > 0) {
        return true;
      }
    }
    return false;
  }

  private void login() {
    Observable.create(new Observable.OnSubscribe<Result<TokenInfo>>() {
      @Override public void call(Subscriber<? super Result<TokenInfo>> subscriber) {
        try {
          loginCall = ServiceGenerator.createService(MockApi.class).login("username", "password");
          Response<Result<TokenInfo>> response = loginCall.execute();
          subscriber.onNext(response.body());
          subscriber.onCompleted();
        } catch (IOException e) {
          subscriber.onError(e);
          e.printStackTrace();
        }
      }
    })
    //SchedulersCompat.<Object>applyIoSchedulers()
      .observeOn(Schedulers.io())
      .subscribeOn(AndroidSchedulers.mainThread())
      .subscribe(new Subscriber<Result<TokenInfo>>() {
        @Override public void onCompleted() {

        }

        @Override public void onError(Throwable e) {
          // 登录失败toast
        }

        @Override public void onNext(Result<TokenInfo> tokenInfoResult) {
          if (tokenInfoResult.hasData() && tokenInfoResult.data.token != null) {
            // TODO 登录成功，存储token
            loadConfig();
          }
        }
      });
  }

  /**
   * 拉取经纪人信息和配置信息
   */
  private void loadConfig() {
    Observable<Result<AgentInfo>> agentObservable =
      ServiceGenerator.createService(MockApi.class).getAgentResponse("$ucId");
    Observable<Result<ConfigInfoVo>> configObservable =
      ServiceGenerator.createService(MockApi.class).getConfigResponse("$ucId");

    Observable.zip(agentObservable, configObservable,
      new Func2<Result<AgentInfo>, Result<ConfigInfoVo>, Boolean>() {
        @Override public Boolean call(Result<AgentInfo> agentInfoResult,
          Result<ConfigInfoVo> configInfoVoResult) {
          LoginActivity.this.agentInfoResult = agentInfoResult;
          LoginActivity.this.configInfoVoResult = configInfoVoResult;
          if (agentInfoResult != null && checkConfig(configInfoVoResult)) {
            // 两个数据都有效才认为是登录成功
            // TODO
            // 保存经纪人信息和config信息到sp中
            return true;
          }
          return false;
        }
      }).observeOn(Schedulers.io())// 指定 subscribe() 发生在 IO 线程
      .subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Boolean>() {
      @Override public void call(Boolean isSuccess) {
        // TODO
        // loading cancel
        if (isSuccess) {
          loginSuccess();
        } else {
          Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
        }
      }
    });
  }

  /**
   * 登录成功
   */
  private void loginSuccess() {
    // TODO
  }

  //public Subscription subscribe(Subscriber subscriber) {
  //  // 伪代码：subscribe方法
  //  subscriber.onStart();
  //  // 当 Observable 被订阅的时候，就会回调OnSubscribe 的 call() 方法
  //  onSubscribe.call(subscriber);
  //  return subscriber;
  //}

  /*private void action(){
    // 解释
    // 自动创建 Subscriber ，并使用 onNextAction 来定义 onNext()
    observable.subscribe(onNextAction);
    // 自动创建 Subscriber ，并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
    observable.subscribe(onNextAction, onErrorAction);
    // 自动创建 Subscriber ，并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()
    observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
  }*/

  private void from() {
    Integer[] arrs = { 1, 2, 3 };
    // 除了 subscribe(Observer) 和 subscribe(Subscriber) ，
    // subscribe() 还支持不完整定义的回调，RxJava 会自动根据定义创建出 Subscriber 。
    Observable.from(arrs).subscribe(new Action1<Integer>() {
      @Override public void call(Integer integer) {
        LogUtil.i(TAG, "call:" + integer);
      }
    });
  }

  private void fun1() {
    Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
      @Override public void call(Subscriber<? super Integer> subscriber) {
        for (int i = 0; i < 3; i++) {
          subscriber.onNext(i);
        }
        // onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理，还会把它们看做一个队列。
        // RxJava 规定，当不会再有新的 onNext() 发出时，需要触发 onCompleted() 方法作为标志。
        subscriber.onCompleted();
      }
    });

    // Observable 通过subscribe方法和Subscriber实现了订阅关系
    Subscription subscription = observable.subscribe(new Subscriber<Integer>() {
      @Override public void onCompleted() {
        LogUtil.i(TAG, "onCompleted");
      }

      @Override public void onError(Throwable e) {

      }

      @Override public void onNext(Integer integer) {
        LogUtil.i(TAG, "onNext:" + integer);
      }
    });

    /*在 RxJava 的默认规则中，事件的发出和消费都是在同一个线程的。也就是说，如果只用上面的方法，实现出来的只是一个同步的观察者模式。
    观察者模式本身的目的就是『后台处理，前台回调』的异步机制，
    因此异步对于 RxJava 是至关重要的。而要实现异步，则需要用到 RxJava 的另一个概念：Scheduler*/

    /*unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法，用于取消订阅。
    在这个方法被调用后，Subscriber 将不再接收事件。
    一般在这个方法调用前，可以使用 isUnsubscribed() 先判断一下状态。
    unsubscribe() 这个方法很重要，因为在 subscribe() 之后， Observable 会持有 Subscriber 的引用，
    这个引用如果不能及时被释放，将有内存泄露的风险。
    所以最好保持一个原则：要在不再使用的时候尽快在合适的地方（例如 onPause() onStop() 等方法中）
    调用 unsubscribe() 来解除引用关系，以避免内存泄露的发生。*/
    // 伪代码
    if (subscription.isUnsubscribed()) {
      subscription.unsubscribe();
    }
  }

  private void schedulers() {
    Integer[] arrs = { 1, 2, 3 };
    // create() 方法是 RxJava 最基本的创造事件序列的方法。基于这个方法， RxJava 还提供了一些方法用来快捷创建事件队列
    // just(T...): 将传入的参数依次发送出来
    // 将会依次调用：
    // onNext("Hello");
    // onNext("Hi");
    // onNext("Aloha");
    // onCompleted();
    Observable.just(1, 2, 3, 4).observeOn(Schedulers.io())// 指定 subscribe() 发生在 IO 线程
      .subscribeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
      .subscribe(new Action1<Integer>() {
        @Override public void call(Integer integer) {

        }
      });
  }

  private void map() {
    Observable.just("imges/icon.png") // 输入类型 String
      .map(new Func1<String, Bitmap>() { // 转化为 Bitmap
        @Override public Bitmap call(String s) {
          //return getBitmapFromPath(filePath); // 返回类型 Bitmap
          return null;
        }
      }).subscribe(new Action1<Bitmap>() {
      @Override public void call(Bitmap bitmap) {
        // 加载bitmap
        //showBitmap(bitmap);
      }
    });
  }

  private void flatMap() {
    Student[] students =
      DataParseUtil.mGson.fromJson(RawUtils.getString(this, R.raw.student), Student[].class);

    Observable.from(students).flatMap(new Func1<Student, Observable<Student.Course>>() {
      @Override public Observable<Student.Course> call(Student student) {
        return Observable.from(student.courseList);
      }
    }).subscribe(new Action1<Student.Course>() {
      @Override public void call(Student.Course course) {
        LogUtil.i(TAG, course.name);
      }
    });
  }

  //private void lift(){
  //  Student[] students =
  //      DataParseUtil.mGson.fromJson(RawUtils.getString(this, R.raw.student), Student[].class);
  //  Observable.from(students).compose()
  //}
}
